>> The security hole in access() is really that it has an implicit race >> condition in it. [...] > The obvious correct coding is to open *first*, then check access, and > close it back up if you shouldn't have opened it. This opens up other problems - you can't do it at all if you use O_CREAT, or you can end up creating files where the user can't. Yes, you can unlink it afterwards, but damage may have been done already, and if you didn't use O_EXCL you can't even tell whether you should do the unlink. (There's no way to do the equivalent of an atomic "test-and-set" open, one which indicates somehow whether the file already existed, but opens/creates it regardless. O_TAS anyone?) And you still can't use access() to do the check, because the symlink may have been switched back. You have to do a very complicated and painful directory tree walk, using lstat/fstat all over the place and I think opening up more races, probably one per directory involved in the walk. Thus, this "obvious correct coding" isn't correct at all; the only correct thing to do is to do the operation under the UID (and GID, for setgid programs) that must be able to perform the operation. If there were some way to perform multiple syscalls atomically with respect to other processes, this might not be necessary, but there isn't. (Except for a few OSes that provide some sort of preemptive high-priority scheduling, and as far as I know all such restrict access to those priorities to processes running as root, and even then usually don't guarantee that nobody else will run while the high-priority process is blocked in the kernel in a syscall.) der Mouse mouse@collatz.mcrcim.mcgill.edu